// This module is licensed and may be used under the terms of the
//  GPL, GNU General Public License, V3 or later, http://www.gnu.org/licenses/gpl.html
//
// Please contact the author if you need another license.
// This module is provided "as is", without warranties of any kind.

import java.io.*;
import java.util.*;
import java.text.*;


/**
 * A simple POP3 client module.
 * 
 * This class is used to communicate with a POP3 server as
 * described in RFC 1939.
 * Project home page: http://code.google.com/p/simple-net-comm/
 * Author: Jonathan Bonazza
 * License: GPL
 */
public class Pop3NetClient extends DefaultNetComm
{
	public Pop3NetComm(String uid, String addr,int port) throws IOException
	{
		super(uid, addr, port);
	}

	/**
	 * @brief: log into server using a specified username and password
	 * @param: the username and password to be authenticated
	 * @return: void
	 */
	public void login(String username, String pass) throws IOException
	{
		//Dump welcome message to console
		System.out.println(recieveMessage());

		//Send user name to server for authentication
		sendMessage("USER: " + username);
		//Expect a response starting with "+OK"
		expect("+OK");
		//Send password to server for authentication
		sendMessage("PASS: " + pass);
		//Expect a response starting with "+OK"
		expect("+OK");
	}

	/**
	 * @brief: retrieve a list of emails from the server
	 * @param: void
	 * @return: A list containing the logged in user's email messages.
	 */
	public List<EmailMessage> fetchEmails() throws IOException
	{
		List<EmailMessage> msgList = new ArrayList<EmailMessage>();

		//Request the number of messages in the user's inbox
		sendMessage("STAT");

		//split the response by a space delemeter
		//[0] = the success response
		//[1] = the number of messages in the user's inbox
		//[2] = the number of bytes the messages total
		String[] tmp = recieveMessage().split(" ");

		//if the server didn't return a success response, 
		//something went wrong; get out
		if(!tmp[0].equals("+OK"))
			throw new IOException();
		
		//Iterate through inbox messages, creating a new EmailMessage for each one		
		for(int i = 0; i < Integer.parseInt(tmp[1]); ++i)
		{
			//Retrieve the current message from the server
			sendMessage("RETR " + i);
			//Expect a response string starting with "+OK"
			expect("+OK");

			boolean header = true;		//are we in the header still?
			String from = null;		//the source address
			String replyTo = null;		//the reply-to address
			String bcc = null;		//The BCC address
			String cc = null;		//The CC address
			String to = null;		//the destination address
			String inReplyTo = null;	//The previous correspondence which the message answers
			String references = null;	//The other correspondence whicht the message references
			String keywords = null;		//Keywords or phrases seperated by commas
			String comments = null;		//Text comments on the message, not part of the body
			Date date = null;		//the date the message was sent
			String subj = null;		//the message subject
			String body = "";		//the message body

			String msg = null;		//temp string for storing each read line

			//read and process a line until end of message reached
			while((msg = recieveMessage()) != ".");
			{
				//If we are no longer in header, 
				//add line to message body
				if(!header)
					body += msg + "\n";
		
				//Otherwise, process further
				else
				{

					//If we read a blank line,
					//then we have reached the body
					if(msg.equals(""))
						header = false;

					//If the line starts with "From" and from hasn't been found yet,
					//then store the source address
					else if(msg.startsWith("From"))
						from = msg.substring(5, msg.length()).trim();

					//If the line starts with "Reply-To",
					//then store the source address
					else if(msg.startsWith("Reply-To"))
						replyTo = msg.substring(9, msg.length()).trim();
	
					//If the line starts with "BCC", then store the BCC address
					else if(msg.startsWith("BCC"))
						bcc = msg.substring(4, msg.length()).trim();
					//If the line starts with "CC", then store the CC address
					else if(msg.startsWith("CC"))
						cc = msg.substring(3, msg.length()).trim();

					//If the line starts with "To",
					//then store the destination address
					else if(msg.startsWith("To"))
						to = msg.substring(3, msg.length()).trim();
	
					//If the line starts with "In-Reply-To", then
					//store the in-reply-to address
					else if(msg.startsWith("In-Reply-To"))
						inReplyTo = msg.substring(12, msg.length()).trim();

					//If the line starts with "References", then store the references
					else if(msg.startsWith("References"))
						references = msg.substring(11, msg.length()).trim();

					//If the line starts with "Keywords", then store the keywords
					else if(msg.startsWith("Keywords"))
						keywords = msg.substring(9, msg.length()).trim();
		
					//If the line starts with "Comments", then store the comments
					else if(msg.startsWith("Comments"))
						comments = msg.substring(9, msg.length()).trim();

					//If the line starts with "Subject",
					//then store the subject
					else if(msg.startsWith("Subject"))
						subj = msg.substring(8, msg.length()).trim();
		
					//If the line starts ith "Date",
					//then storet the date
					else if(msg.startsWith("Date"))
					{
						//formate the date appropriately
						SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yy hh:mm:ss");
						date = sdf.parse(msg.substring(5, msg.length()).trim());
					}
				}
				
				//Create a new EmailMessage object with the obtained information
				EmailMessage tmpMsg = new EmailMessage(from, to, date, subj, body);

				//Request the message's UIDL			
				sendMessage("UIDL " + i);
				
				//Splite the response by a " "  delimeter
				//[0] = the success of the command
				//[1] = the UIDL
				//[2] = the number of bytes (ignored)
				String[] res = recieveMessage().split(" ");

				//if the reponse returned success,
				//then store the UIDL
				if(res[0].equals("+OK"))
					tmpMsg.setUIDL(res[1]);

				//Add the newly created EmailMessage to the list
				msgList.add(tmpMsg);
			}

		}

		return msgList;
	}

	/**
	 * @brief: Quits the POP3 session and implicitly logs out
	 * @param: void
	 * @return: void
	 */
	public void quit() throws IOException
	{
		//Request quit
		sendMessage("QUIT");		
		//Confirm that we successfully quit
		expect("+OK");
	}

}
